/**
 * 
 */
package com.massyframework.beanskin.launcher.scanning.maven;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.massyframework.beanskin.ModuleIdentifier;
import com.massyframework.beanskin.launcher.deploying.OsNameUtils;

/**
 * {@link DevelopingMavenProject},正在开发中的Maven项目
 * @author huangkh
 *
 */
class DevelopingMavenProject extends MavenProject {
	
	private static Logger LOG = LoggerFactory.getLogger(DevelopingMavenProject.class);
	private static final String CLASSES    = "target".concat(File.separator).concat("classes");
	private static final String LIB        = "lib";

		
	private final File baseDir;
	private final ParentCoordinate parent;
	
	private final List<String> modules;
	private final Map<String, String> properties;
	private final boolean isPomProjoect;
	private final boolean isCopyDependencies;
	private final List<ArtifactItem> artifactItems;
	
	protected AbstractMavenProjectRepository mavenProjectRepository;
	
	private boolean refreshed = false;
	
	/**
	 * 使用{@code builder}创建新实例
	 * @param builder {@link Builder}
	 */
	protected DevelopingMavenProject(Builder builder) {
		super(builder);
		this.baseDir = Objects.requireNonNull(builder.baseDir, "\"baseDir\" cannot be null.");
		this.parent = builder.parent == null ? null : builder.parent;
		this.isPomProjoect = builder.isPomProject;
		this.modules = builder.modules;
		this.isCopyDependencies = builder.isCopyDependencies;
		this.artifactItems = builder.artifactItems == null ? Collections.emptyList() : builder.artifactItems;
		this.mavenProjectRepository = Objects.requireNonNull(builder.mavenProjectRepository, "\"mavenProjectRepository\" cannot be null.");
		this.properties = builder.properties == null ?
				new LinkedHashMap<>():
					builder.properties;
		this.properties.put("project.version", this.getCoordinate().getVersion());
	}
	
	/**
	 * 项目工程目录
	 * @return {@link File}
	 */
	public File getBaseDir() {
		return this.baseDir;
	}
	
	/**
	 * 所属父工程的坐标
	 * @return {@link ParentCoordinate} 
	 */
	public ParentCoordinate getParentCoordinate() {
		return this.parent;
	}
	
	/**
	 * 获取{@code name}对应的属性
	 * @param name {@link String}
	 * @return {@link String}
	 */
	public String getProperty(String name) {
		if (this.properties.containsKey(name)) {
			return this.properties.get(name);
		}
		
		DevelopingMavenProject parent = this.getParent();
		if (parent != null) {
			return parent.getProperty(name);
		}
		
		return null;
	}
	
	/**
	 * 模块名称
	 * @return {@link List}
	 */
	public List<String> getModuleNames(){
		return this.modules == null ?
				Collections.emptyList() :
					Collections.unmodifiableList(this.modules);
	}
	
	/**
	 * 复制到目录下的工程。
	 * @return {@link List}
	 */
	public List<ArtifactItem> getArtifactItems(){
		return this.artifactItems == null ?
				Collections.emptyList() :
					Collections.unmodifiableList(this.artifactItems);
	}
	
	/**
	 * 是否pom工程
	 * @return {@link boolean}
	 */
	public boolean isPomProject() {
		return this.isPomProjoect;
	}
	
	/**
	 * 获取上级工程
	 * @return {@link DevelopingMavenProject}
	 */
	public DevelopingMavenProject getParent() {
		if (this.parent != null) {
			MavenProject project = 
					this.mavenProjectRepository
						.findMavenProject(this.parent, false);
			if (project != null) {
				if (project instanceof DevelopingMavenProject) {
					return (DevelopingMavenProject)project; 
				}
			}
		}
		
		return null;
	}
	
	@Override
	public List<URL> getOutputFiles(ModuleIdentifier identifier) {
		this.refresh();
		
		List<URL> result = new ArrayList<>();
		if (!this.getArtifactItems().isEmpty()) {
			for (ArtifactItem artifact: this.artifactItems) {
				MavenProject project = 
						this.mavenProjectRepository
							.findMavenProject(artifact, true);
				if (project != null) {
					result.addAll(project.getOutputFiles(identifier));
				}else {
					if (LOG.isErrorEnabled()) {
						LOG.error("cannot found maven project:" + artifact + ".");
					}
				}
			}
		}else {
			if (this.isCopyDependencies) {
				File classesDir = new File(this.baseDir, CLASSES);
				File libDir = this.foundLibDir(classesDir);
				if (libDir != null) {
					File[] jars = libDir.listFiles( f -> f.getName().endsWith(".jar"));
					for (File jar: jars) {
						try {
							result.add(jar.toURI().toURL());
						}catch(Exception e) {
							
						}
					}
				}
			}else {
				try {
					String name = "target".concat(File.separator).concat("classes")
								.concat(File.separator).concat("MODULE").concat(File.separator)
								.concat(identifier.getGroupId()).concat(File.separator).concat(identifier.getModuleId())
								.concat(File.separator).concat(identifier.getVersion().toString()).concat(File.separator)
								.concat("lib");
					File file = new File(baseDir, name);
					if (!file.exists()) {
						file = new File(baseDir, CLASSES);
						result.add(file.toURI().toURL());
					}else {
						this.listJarFiles(file, OsNameUtils.getOsName(), result);
					}
					
				} catch (MalformedURLException e) {
			
				}
			}
		}
		
		return result;
	}
	
	protected void listJarFiles(File dir, String osName, List<URL> jarUrls) throws MalformedURLException {
		File[] files = dir.listFiles();
		for (File file: files) {
			if (file.isFile()) {
				if (file.getName().endsWith(".jar")) {
					jarUrls.add(file.toURI().toURL());
				}
			}else {
				if (osName == null) continue;
				if (file.getName().equals(osName)) {
					this.listJarFiles(file, null, jarUrls);
				}
			}
			
		}
	}
	
	/**
	 * 发现定位lib目录
	 * @param dir
	 * @return
	 */
	protected File foundLibDir(File dir) {
		if (dir == null) return null;
		
		File[] files = dir.listFiles();
		if (files == null) return null;
		
		for (File file: files) {
			if (file.isDirectory()) {
				if (LIB.equals(file.getName())) {
					return file;
				}else {
					File result = this.foundLibDir(file);
					if (result != null) {
						return result;
					}
				}
			}
		}
		
		return null;
	}
	
	/**
	 * 刷新
	 * <p>
	 * 更新变量
	 */
	protected synchronized void refresh() {
		if (!this.refreshed) {
			DevelopingMavenProject parent = this.getParent();
			if (parent != null) {
				parent.refresh();
			}
			
			//更改属性变量
			this.refreshProperties();
			//更改复制工程的版本变量
			this.refreshArtifactItems();
			this.refreshed = true;
		}
	}
	
	/**
	 * 刷新属性
	 */
	protected void refreshProperties() {
		for (Map.Entry<String, String> entry: this.properties.entrySet()) {
			String value = this.replaceVariable(entry.getValue());
			entry.setValue(value);			
		}
	}
	
	protected void refreshArtifactItems() {
		List<ArtifactItem> tmp = new ArrayList<>(this.artifactItems);
		this.artifactItems.clear();
		for (ArtifactItem item: tmp) {
			String version = item.getVersion().trim();
			if (version.startsWith("$")) {
				String name = version.substring(2, version.length()-1);
				version = this.getProperty(name);
				if (version == null) {
					if (LOG.isErrorEnabled()) {
						LOG.error("cannot found property: name=" + name + ".");
					}
				}
				this.artifactItems.add(
						ArtifactItem.newBuilder(item).version(version).build());
			}else {
				this.artifactItems.add(item);
			}
		}
	}
	
	/**
	 * 替换变量
	 * @param value {@link String}
	 * @return {@link String}
	 */
	protected String replaceVariable(String value) {
		StringBuffer buff = new StringBuffer();
		Matcher m = Pattern.compile("\\$\\{\\w+\\}").matcher(value);
		while (m.find()) {
	        String param = m.group();
	        String text = this.getProperty(param.substring(2, param.length() - 1));
	        m.appendReplacement(buff, text==null ? "" : text);
	    }
	    m.appendTail(buff);
	    return buff.toString();
	}
	
		
	/**
	 * 创建构建器 
	 * @return {@link Builder}
	 */
	public static Builder newBuilder() {
		return new Builder();
	}

	public static class Builder extends MavenProject.Builder {
		
		protected File baseDir;
		protected boolean isPomProject = false;
		protected ParentCoordinate parent;
		protected AbstractMavenProjectRepository mavenProjectRepository;
		protected Map<String, String> properties;
		protected List<String> modules;
		protected boolean isCopyDependencies = false;
		protected List<ArtifactItem> artifactItems;
	
		
		@Override
		public Builder coordinate(Coordinate coordinate) {
			super.coordinate(coordinate);
			return this;
		}

		/**
		 * 设置开发项目的基本目录
		 * @param dir {@link File}
		 * @return {@link Builder}
		 */
		public Builder baseDir(File dir) {
			if (!dir.isDirectory()) {
				throw new IllegalArgumentException("\"dir\" isnot a directory.");
			}
			this.baseDir = dir;
			return this;
		}
		
		/**
		 * 设置父Maven项目
		 * @param parent {@link DevelopingMavenProject}
		 * @return {@link Builder}
		 */
		public Builder parent(ParentCoordinate parent) {
			this.parent = parent;
			return this;
		}
		
		/**
		 * 设置项目属性
		 * @param props {@link Map}
		 * @return {@link Builder}
		 */
		public Builder properties(Map<String, String> props) {
			this.properties = props;
			return this;
		}
		
		/**
		 * 设置是否pom工程
		 * @param isPomProject {@link boolean}
		 * @return {@link Builder}
		 */
		public Builder isPomProject(boolean isPomProject) {
			this.isPomProject = isPomProject;
			return this;
		}
		
		/**
		 * 设置maven项目仓储
		 * @param value {@link DefaultMavenProjectRepository}
		 * @return {@link Builder}
		 */
		public Builder mavenProjectRepository(AbstractMavenProjectRepository value) {
			this.mavenProjectRepository = value;
			return this;
		}
		
		/**
		 * 设置子模型名
		 * @param modules {@link List}
		 * @return {@link Builder}
		 */
		public Builder modules(List<String> modules) {
			this.modules = modules;
			return this;
		}
		
		/**
		 * 设置是否复制依赖
		 * @param value {@link Boolean}
		 * @return {@link Builder}
		 */
		public Builder isCopyDependencies(boolean value) {
			this.isCopyDependencies = value;
			return this;
		}
		
		/**
		 * 设置复制的工程
		 * @param items {@link List}
		 * @return {@link Builder}
		 */
		public Builder artifactItems(List<ArtifactItem> items) {
			this.artifactItems = items;
			return this;
		}
		
		/**
		 * 创建开发中maven项目的实例
		 * @return {@link DevelopingMavenProject}
		 */
		public DevelopingMavenProject build() {
			return new DevelopingMavenProject(this);
		}
	}
}
